﻿using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using Logistics.DataManage;
using NPOI.HSSF.UserModel;
using log4net;
using System.Runtime.InteropServices;

namespace Logistics.Print
{
    public class PrintTemplate
    {
        private static ILog Log = LogManager.GetLogger(typeof(PrintTemplate).FullName);
        private static object oMissing = Missing.Value;
        
        private static Regex regex = new Regex(@"\{\$\..*\}",RegexOptions.Multiline | RegexOptions.IgnoreCase);

        public static String GenerateBillFileForPrint(String BillId, String TemplatePath)
        {
            if (String.IsNullOrEmpty(BillId) || String.IsNullOrEmpty(TemplatePath))
                throw new ArgumentNullException("Argument BillId or TemplatePath is empty");
            if (!File.Exists(TemplatePath))
                throw new ArgumentException("无法找到打印模版文件：" + TemplatePath);

            PrintContext pctx = new PrintContext(BillId);
            Hashtable PrintCtx = pctx.GetHashContext();
            
            String target = Path.Combine(Path.GetTempPath(),Guid.NewGuid().ToString()+".xls");
            File.Copy(TemplatePath, target);

            bool success = FillTemplate(target, PrintCtx);
            return target;
        }
        private static bool FillTemplate(String filePath, Hashtable context)
        {
            if (!File.Exists(filePath))
                return false;
            HSSFWorkbook hssfworkbook = null;
            using (Stream iExcelFile = File.Open(filePath, FileMode.Open, FileAccess.Read))  
            { 
                hssfworkbook = new HSSFWorkbook(iExcelFile);
            }
            if (hssfworkbook == null)    
                throw new IOException("打开指定的文件出错!"+filePath);

            try
            {
                HSSFSheet sheet = hssfworkbook.GetSheetAt(0) as HSSFSheet;
                String end = GetRightBittomCell(sheet);
                String[] ends = end.Split('-');
                int lastRow = Convert.ToInt32(ends[0]);
                int lastCol = Convert.ToInt32(ends[1]);
                for (int i = 0; i < lastRow; i++)
                {
                    HSSFRow iRow = (HSSFRow)sheet.GetRow(i);
                    if (iRow == null) continue;
                    for (Int32 j = 0; j < lastCol; j++)
                    {
                        HSSFCell iCell = (HSSFCell)iRow.GetCell(j);
                        if (iCell == null) continue;
                        FilleTemplateCell(context, iCell);
                    }
                }
                //保存
                using (FileStream iFile = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                {
                    hssfworkbook.Write(iFile);
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                
            }
            return true;
        }

        private static void FilleTemplateCell(Hashtable context, HSSFCell cell)
        {
            if (cell == null) return;
            String text = cell.StringCellValue;
            bool update = false;
            while (regex.IsMatch(text))
            {
                update = true;
                Match m = regex.Match(text);
                String express = m.Value;
                DynamicExpress exp = new DynamicExpress(express, context);
                String val = exp.Eval();
                text = text.Replace(express, val);
            }
            if (update)
                cell.SetCellValue(text);
        }

        /// <summary>
        /// 获取最后一行最后一列
        /// </summary>
        /// <param name="sheet"></param>
        /// <returns></returns>
        private static String GetRightBittomCell(HSSFSheet sheet)
        {
            for (Int32 i = 0; i <= 200; i++)
            {
                HSSFRow iRow = (HSSFRow)sheet.GetRow(i);
                if (iRow == null)
                    continue;
                for (Int32 j = 0; j < 100; j++)
                {
                    HSSFCell iCell = (HSSFCell)iRow.GetCell(j);
                    if (iCell == null)
                        break;

                    if (String.Compare("#End", iCell.StringCellValue, true) == 0)
                    {
                        iCell.SetCellValue("");
                        return i + "-" + j;
                    }
                }
            }
            return "100-100";
        }
        
        /// <summary>
        /// 打印Excel
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="printerName"></param>
        /// <param name="copies"></param>
        public static void PrintExcel(String filePath,String printerName,int copies,String printToFileLocation)
        {
            Microsoft.Office.Interop.Excel.Application oExcel = null;
            Microsoft.Office.Interop.Excel.Workbooks oBooks = null;
            Microsoft.Office.Interop.Excel.Workbook oBook = null;

            try
            {
                oExcel = new Microsoft.Office.Interop.Excel.Application();
                oBooks = oExcel.Workbooks;
                oExcel.Visible = false;

                //不弹出警告框
                oExcel.DisplayAlerts = false;
                oBook = oBooks.Open(filePath, oMissing, oMissing,
                        oMissing, oMissing, oMissing, oMissing, oMissing, oMissing,
                        oMissing, oMissing, oMissing, oMissing, oMissing, oMissing);
                Microsoft.Office.Interop.Excel._Worksheet worksheet = (Microsoft.Office.Interop.Excel._Worksheet)oBook.Sheets.Item[1];
                //打印
                copies = copies > 0 ? copies : 1;
                bool preview = false;
                if (String.IsNullOrWhiteSpace(printerName))
                    printerName = oExcel.ActivePrinter;
                bool printToFile = false;
                Object printToFilePath = oMissing;
                if (!String.IsNullOrEmpty(printToFileLocation))
                {
                    printToFile = true;
                    printToFilePath = printToFileLocation;
                }
                worksheet.PrintOut(oMissing, oMissing, copies, preview, printerName, printToFile, 1, printToFilePath);
                
                bool saveChanges = false;
                oBook.Close(saveChanges, oMissing, oMissing);
                Marshal.FinalReleaseComObject(oBook);
            }
            catch (Exception ex)
            {
                Log.Error("打印错误", ex);
                throw ex;
            }
            finally
            {
                if (oExcel!=null)
                    oExcel.Quit();

                Marshal.FinalReleaseComObject(oExcel);
                oBook = null;
                oExcel = null;
                GC.Collect();
                GC.WaitForPendingFinalizers();
                
            }
        }
    }
}
